/************************************************************
 * UPGRADE
 *  GUF - Ginko Upgrade File (.guf)
 ************************************************************
 *
 * |--------------------|
 * |       header       | -> obfuse
 * |--------------------|
 * | file-1 binary data |
 * |    ... ... ...     | -> encrypt
 * | file-N binary data |
 * |--------------------|
 * |   integrity check  | -> original
 * |--------------------|
 *
 ************************************************************/
#ifndef _GKT_UPGRADE_H_
#define _GKT_UPGRADE_H_

#include "gkt_types.h"

#define GKT_GUF_MAGIC_V1	0x475546C1

/* type */
enum {
	GKT_GUF_TYPE_APP = 0,
	GKT_GUF_TYPE_VOICE_CHN,
	GKT_GUF_TYPE_VOICE_ENG,
	GKT_GUF_TYPE_CONFIG,
	GKT_GUF_TYPE_MAX
};


/* data encrypt mode - refer to gkt_crypto_mode_e */
enum {
	GKT_GUF_ENCRYPT_MODE_ECB = 0,	/* Electronic Codebook Book */
	GKT_GUF_ENCRYPT_MODE_CBC,	/* Cipher Block Chaining */
	GKT_GUF_ENCRYPT_MODE_CTR,	/* Counter */
	GKT_GUF_ENCRYPT_MODE_CFB,	/* Cipher FeedBack */
	GKT_GUF_ENCRYPT_MODE_OFB,	/* Output FeedBack */
	GKT_GUF_ENCRYPT_MODE_MAX
};

/* data encrypt algorithm */
enum {
	GKT_GUF_ENCRYPT_ALGORITHM_NONE = 0,
	GKT_GUF_ENCRYPT_ALGORITHM_AES128,	/* key, IV, block: 128bits */
	GKT_GUF_ENCRYPT_ALGORITHM_AES192,	/* key: 192bits, IV, block: 128bits */
	GKT_GUF_ENCRYPT_ALGORITHM_AES256,	/* key: 256bits, IV, block: 128bits */
	GKT_GUF_ENCRYPT_ALGORITHM_MAX
};

#define GKT_GUF_ENCRYPT_KEY_MAXSIZE	32
/*
 * AES128 Key: "${GUF_V1}-AES128-K-${hw_mainboard_version}-${hw_daughter_board}-${client_usage}-${checksum}"
 *     { 0x47, 0x55, 0x46, 0xC1, 0x41, 0x45, 0x53, 0x10, 0x4B, ... }
 * AES192 Key: "${GUF_V1}-AES192-K-${hw_mainboard_version}-${hw_daughter_board}-${client_usage}-${obfuse_init}
 *                -"A"-${enc_algo}-"M"-${enc_mode}-"P"-${enc_padding}-${IV_checksum}-${checksum}"
 *     { 0x47, 0x55, 0x46, 0xC1, 0x41, 0x45, 0x53, 0x18, 0x4B, ... }
 * AES256 Key: "${GUF_V1}-AES256-K-${hw_mainboard_version}-${hw_daughter_board}-${client_usage}-${obfuse_init}
 *                -"A"-${enc_algo}-"M"-${enc_mode}-"P"-${enc_padding}-${IV_checksum}
 *                -${item_infos[0]}-${checksum}"
 *     { 0x47, 0x55, 0x46, 0xC1, 0x41, 0x45, 0x53, 0x20, 0x4B, .. }
 */

/* data encrypt padding */
enum {
	GKT_GUF_ENCRYPT_PADDING_NONE = 0,
	GKT_GUF_ENCRYPT_PADDING_ZERO,
	GKT_GUF_ENCRYPT_PADDING_PKCS7,
	GKT_GUF_ENCRYPT_PADDING_MAX
};

/* data encrypt IV if algorithm needs */
#define GKT_GUF_ENCRYPT_IV_MAXSIZE	16

/* integrity checking */
enum {
	GKT_GUF_INTEGRITY_CHECK_NONE = 0,
	GKT_GUF_INTEGRITY_CHECK_CRC32,
	GKT_GUF_INTEGRITY_CHECK_MD5,
	GKT_GUF_INTEGRITY_CHECK_SHA1,
	GKT_GUF_INTEGRITY_CHECK_SHA256,
	GKT_GUF_INTEGRITY_CHECK_MAX
};

typedef struct {
	uint32_t	type : 4;	/* GKT_GUF_TYPE_APP/CONFIG/VOICE */
	uint32_t	sub_id : 4;	/* App: 0, Voice: 0(CHN), 1(ENG), ..., Config: 0 */

	uint32_t	total_size : 24;	/* real size, < 16M */

	/*
	 * APP - major(8-bits, <100).minor(8-bits, <100).revision(8-bits, <100)
	 *   V4.1.23 -> 0x00_04_01_17
	 *   V12.9.1 -> 0x00_0C_09_01
	 * Voice - year(16-bits)-month(8-bits)-day(8-bits)
	 *   2023-07-01 -> 0x07E7_07_01
	 *   2023-11-25 -> 0x07E7_0B_19
	 */
	uint32_t	version;
} gkt_upgrade_item_info_s;
typedef struct {
	/* matched mainboard version
	 *   version(V, 4-bits * 3, 0 ~ F)-batch number(P, 4-bits, 0 ~ F)
	 *     V00EP4 -> 0x00E4
	 *     V1F5PD -> 0x1F5D
	 */
	uint16_t	hw_mainboard_version;

	/* daughter board
	 *   "DP"(0x4450) - semi-automatic smartlock, Discrete Plate, e.g: V003P4
	 *   "SP"(0x5350) - semi-automatic smartlock, Single Plate, e.g: V003P7, V005P2
	 *   "B1"(0x4231) - automatic smartlock, basic version 1
	 *   "M1"(0x4D31) - automatic smartlock, electronic cat's eye version 1
	 *   ...
	 */
	uint16_t	hw_daughter_board;

	/* client or usage
	 *   "GB"(0x4742) - Public version
	 *   "CS"(0x4353) - Test version
	 *   "KX"(0x4B58) - for client kehon
	 *   ...
	 */
	uint16_t	client_usage;	/* "GB", "KX", "CS" */

	uint16_t	reserved;
}gkt_guf_product_id_s;
typedef struct {
	uint32_t	magic;

	uint8_t	obfuse_init;

	uint8_t	reserved_0;

	gkt_guf_product_id_s product_id;

	gkt_upgrade_item_info_s	item_infos[GKT_GUF_TYPE_MAX];

	uint8_t	integrity_check_type : 4;
	uint8_t	data_encrypt_algorithm : 4;
	uint8_t	data_encrypt_mode : 4;
	uint8_t	data_encrypt_padding_type : 4;
	uint8_t	data_encrypt_IV[GKT_GUF_ENCRYPT_IV_MAXSIZE];

	uint32_t guf_crc32;
} gkt_guf_header_s;

#define GKT_GUF_PACKET_SIZE_MAX 128

int gkt_upgrade_init(void);
int gkt_upgrade_parse_guf_header(const uint8_t data[], gkt_guf_header_s *guf_header);
int gkt_upgrade_save_data_to_flash(const uint8_t data[], uint32_t offset, uint32_t lenght);
int gkt_upgrade_check_crc16(int16_t crc, const uint8_t data[], uint32_t lenght);

#endif
